RDS Proxyを使ってAWS LambdaからRDBにコネクションプールで接続する
Amazon RDS Proxyはパブリックプレビュー機能です。 正式公開までに機能が大幅に変更される可能性があります。
昨年末に開催されたre:invent 2019でAmazon RDS向けの完全マネージド型で可用性の高いデータベースプロキシ「Amazon RDS Proxy」が公開されました。 コネクションプーリングや自動フェイルオーバーなどを完全マネージドで利用できます。
[速報]これでLambdaのコネプー問題も解決?!LambdaからRDS Proxyを利用できるようになりました(まだプレビュー) #reinvent
RDS Proxyがもっとも威力を発揮するユースケースがAWS Lambdaからリレーショナルデータベースへの接続です。
このユースケースに特化したウェビナー ”Using Relational Databases with AWS Lambda - Easy Connection Pooling - AWS Online Tech Talks” を見つけたので、雑にまとめました。
※ 本レポートの画像はすべて YouTube からの加工です。
AWS LambdaからRDBに接続するときの課題
課題
- DB接続のたびに、DBサーバーはメモリやコンピュートリソースを消費
- AWS Lambda 関数 のようなサーバーレスアプリケーションは短時間に何万ものDB接続を行う
- DBサーバーのクライアントからのDB接続のために多くのリソースを消費してしまい、クエリー実行に十分なリソースを割り当てられない
解決策
2つの解決策
- DBプロキシーを構築
- 接続のオーバーヘッドを軽減するため、コネクションプールを導入・運用
- Lambda 関数にDB接続のロジックを用意
- 接続エラー時のリトライ、タイムアウトなど
- クレデンシャルなども含む
これらのソリューションは、運用が大変で、実装に工数がかかる。つまるところ、ビジネスのコア以外のところに時間を取られすぎる。
データベース接続の具体例
DBに接続するクライアントは
- AWS Lambda
- Amazon EC2
- Amazon ECS
などで動作することが考えられます。
アプリケーションが小規模なら、RDB への接続数も少なく、SQL実行で問題は起きない。
イベントなどの場合は、RDB への SQL 問い合わせがスパイクする
DB 接続のためにDB サーバーのメモリ・コンピューティングリソースが費やされ、SQL を実行するリソースが欠如する。
RDBへの問い合わせを減らすため、Redis(Amazon ElastiCache)のようなインメモリキャッシュを導入。
キャッシュの期限切れやキャッシュミス時にはDB問い合わせが発生する。 DB問い合わせを早く、かつ、負荷を少なく行うために、コネクションプールを導入。
このような構成を構築・運用するには、エンジニアのリソースがたくさん必要
Amazon RDS Proxyがこれらの課題を解決
Amazon RDS プロキシは、Amazon RDS 向けの完全マネージド型で可用性の高いデータベースプロキシ
- AWS Lambda のようなサーバーレスアーキテクチャーを利用する現代的なアプリケーションは数秒間で何千・何万ものDB接続を行う
- 従来の接続方式だと、DBサーバーのリソースが簡単に枯渇してしまう
- RDS Proxyのウォーム状態のコネクションプールを利用することで、データベースリソースを効率的に使用できる
- RDS Proxyは負荷に応じて自動的にスケールする
- DBの認証情報はAWS Secrets Managerで管理し、アプリケーションにハードコードしないのでセキュリティが向上
- さまざまなデータベースエンジンに対応
対応データベースエンジン・リージョン
データベースエンジン
- RDS/Aurora MySQL : 5.6/5.7
- RDS/Aurora PostgreSQL : まもなく対応予定
リージョン
- 東京
- ダブリン
- 北部バージニア
- オハイオ
- オレゴン
Amazon RDS ProxyとAWS Lambaを連携した構成図
- コネクションプール
- RDS Proxy はアプリケーションと Amazon RDS の間に位置する
- RDS Proxy がコネクションプールを管理
- DB接続周りの複雑なロジックを Lambda に書かなくてすむ
- Lambda はビジネスロジックを書くだけ
- 認証情報
- クレデンシャルはAWS Secrets Managerで管理
- Lambda内にクレデンシャルを組み込まなくて良い
- 通信の暗号化
- DBエンジンとの通信が暗号化(TLS通信)されていなくても、クライアント→RDS Proxy間の通信を暗号化(TLS化)できる
RDS Proxyへの認証は2方式
- DBネイティブの認証
- エンドポイントが RDS から RDS Proxy に変わるだけ
- クライアントのロジックはバックエンドのDBに接続する場合と同じ
- ライブラリの追加などはいらない
- IAM 認証
- RDS IAM認証と同じ
- 永続的な認証情報は利用しない
- 接続のたびにワンタイムトークンを取得して認証
個人的な印象としては、DBネイティブの認証を利用すると、アプリの改修範囲を抑えられるため、RDS Proxyの導入の敷居が下がると思います。
認証情報は RDS Proxy 向けの Secrets Manager に相乗りして Lambda から外だしし、Secrests Manager API のスロットリング回避のためにクライアント側でキャッシュすれば最小限の改修にはなるのではないかと。
IAM 認証を利用すると、一時認証の取得・期限切れ時の更新、IAM認証APIのスロットリング回避、といったロジックをクライアントで実装する必要があり、本番で安定運用させるには、地味に手間がかかりそうな印象です。
CloudWatch メトリクス
有用なメトリクス
- ClientConnections : クライアントからRDS Proxyへの接続数
- QueryRequests : クライアントからRDS Pxoryへのクエリー数
- DatabaseConnections : RDS ProxyからRDSへの接続数
- RDS ProxyはRDSインスタンスへの接続を多重化
- クライアントからRDS Proxyへの接続(ClientConnections)が増えても、RDS ProxyからRDSへの接続(DatabaseConnections)を抑える
利用費
- バックエンドRDSのインスタンスタイプの vCPU によって時間単価が変わる
- 例えば東京リージョンの場合、1vCPU の時間単価は $0.018
- インスタンスタイプが r5.24xlarge の場合、vCPU は 96 個。時間単価は $0.018 * 96 = $1.728/hour
- 30日換算すると $1.728/hour * 24 hour * 30 days = $1,244.16/month
RDS Proxyのレイテンシーは5ms
Q: データベースには、Amazon RDS プロキシの使用ではなく直接接続をいつする必要がありますか?
ワークロードに応じて、Amazon RDS プロキシはクエリまたはトランザクションの応答時間に平均 5 ミリ秒のネットワークレイテンシーを追加できます。アプリケーションが 5 ミリ秒のレイテンシーを許容できない場合、またはRDS プロキシによって有効になっている接続管理やその他の機能が必要ない場合、アプリケーションをデータベースエンドポイントに直接接続することが可能です。